/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "node.h"

namespace tri {
namespace node {

unsigned int Node::node_count = 0;

Node::Node() :
    prev_node(NULL), next_node(NULL), child_node(NULL) {
    node_id=++node_count;
}
Node::~Node() {
    Node* rn = getRootNode();
    if (rn != NULL) {
        rn->removeNode(this);
    }
    while (child_node != NULL) {
        removeNode(child_node);
    }
}

Node* Node::getPrevNode() {
    return prev_node;
}

Node* Node::getNextNode() {
    return next_node;
}

Node* Node::getChildNode() {
    return child_node;
}

Node* Node::getLeafNode() {
    if (prev_node == NULL) {
        return NULL;
    }
    if (next_node != NULL) {
        return next_node->getLeafNode();
    }
    return this;
}

Node* Node::getRootNode() {
    if (prev_node == NULL&& child_node == NULL) {
        return NULL;
    }

    if (prev_node != NULL) {
        if (prev_node->getChildNode() == this) {
            return prev_node;
        } else {
            return prev_node->getRootNode();
        }
    }
    return NULL;
}

bool Node::compareNodeID(Node* n) {
    if (n->node_id == node_id) {
        return true;
    }
    if (next_node != NULL) {
        return next_node->compareNodeID(n);
    }
    return false;
}

bool Node::inChildNode(Node* n) {
    if (child_node == NULL) {
        return false;
    }

    return child_node->compareNodeID(n);
}

bool Node::inChildNodeRecursive(Node* n) {
    if (n->node_id == node_id) {
        return true;
    }

    if (child_node != NULL) {
        if (child_node->inChildNodeRecursive(n)) {
            return true;
        }
    }

    if (next_node != NULL) {
        return next_node->inChildNodeRecursive(n);
    }
    return false;
}

void Node::addNode(Node* n) {
    assert(n!=NULL);
    assert(n!=this);
    Node* rn = getRootNode();
    if (rn != NULL) {
        assert(!rn->child_node->compareNodeID(n));
    }
    Node* nrn = n->getRootNode();
    if (nrn != NULL) {
        nrn->removeNode(n);
    }

    n->prev_node = NULL;
    n->next_node = NULL;

    if (child_node == NULL) {
        child_node = n;
        child_node->prev_node = this;
    } else {
        if (child_node->prev_node == NULL) {
            child_node->prev_node = this;
        }
        Node* ln = child_node->getLeafNode();
        assert(ln!=NULL);
        ln->next_node = n;
        n->prev_node = ln;
        assert(child_node->getLeafNode() == n);
    }
}

void Node::removeNode(Node* n) {
    if (inChildNode(n)) {
        Node* _p = n->prev_node;
        Node* _n = n->next_node;
        n->prev_node = NULL;
        n->next_node = NULL;

        //if n is the first node
        if (_p==this) {
            //if n was also the leaf node
            //else reconnect nodes
            if (_n == NULL) {
                child_node = NULL;
            } else {
                _n->prev_node = _p;
                child_node = _n;
            }
        } else {
            //if n was also the leaf node
            //else reconnect nodes
            if (_n == NULL) {
                _p->next_node = NULL;
            } else {
                _n->prev_node = _p;
                _p = _n;
            }
        }

        assert(n->next_node == NULL);
        assert(n->prev_node == NULL);

    }
}

}
}
